package com.meiwenhui.ibatis.extend.util;

import java.io.IOException;
import java.io.Reader;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class SessionFactoryUtil {

	/**
	 * Parameter used to define the XML Hibernate configuration file
	 */
	private static final String IBATIS_CONFIGURATION_FILE_PROPERTY = "ibatis-config.xml";

	/**
	 * Class logger
	 */
	private static Log log = LogFactory.getLog(SessionFactoryUtil.class);

	/**
	 * The one and only session manager instance
	 */
	private static SessionFactoryUtil sessionFactoryUtil = new SessionFactoryUtil();
	/**
	 * The one and only Hibernate session factory.
	 */
	private static final SqlSessionFactory sessionFactory;

	static {
		try {
			// Create the SessionFactory
			Reader reader = Resources.getResourceAsReader(IBATIS_CONFIGURATION_FILE_PROPERTY);
			sessionFactory = new SqlSessionFactoryBuilder().build(reader);
		} catch (Exception ex) {
			throw new RuntimeException("Configuration problem: " + ex.getMessage(), ex);
		}
	}

	/**
	 * The thread-local Hibernate session object
	 */
	private static final ThreadLocal threadSession = new ThreadLocal();

	public static SqlSession getSession() throws Exception {
		return currentSession();
	}

	public static SqlSession currentSession() throws Exception {
		log.debug("Hibernate Session Manager :Fetching a hibernate session");
		SqlSession s = (SqlSession) threadSession.get();
		// Open a new Session, if this Thread has none yet
		if (s == null) {
			s = sessionFactory.openSession();
			threadSession.set(s);
		}
		log.debug("Hibernate Session Manager :Fetching a hibernate session done.");
		return s;
	}

	/**
	 * Close the current Hibernate session
	 * 
	 * @throws HibernateException
	 * @throws InfrastructureException
	 */
	public static void closeSession() {
		log.debug("Hibernate Session Manager : closeSession");
		SqlSession s = (SqlSession) threadSession.get();
		threadSession.set(null);
		if (s != null) {
			log.debug("Hibernate Session Manager : closing session");
			s.close();
			log.debug("Hibernate Session Manager : session closed");
		}
		s = null;
	}

	/**
	 * Default constructor
	 */
	private SessionFactoryUtil() {
		super();
	}

	/**
	 * Returns an instance of a session mananger used to obtain a Hibernate
	 * Session object.
	 * 
	 * @return the Hibernate session manager.
	 */
	public static SessionFactoryUtil getInstance() {
		return sessionFactoryUtil;
	}

	public static SqlSession openSession() throws Exception {
		return SessionFactoryUtil.currentSession();
	}

	// -- test -- //

	public static void main(String[] args) throws IOException {
		for (int i = 0; i < 10; i++) {
			System.out.println(SessionFactoryUtil.getInstance());
		}
	}
}
